package org.zoomdev.zoom.dao.ddl;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;

public enum SqlType {
    // ==================== 数字类型 ====================
    INT(Types.INTEGER, Integer.class),
    INT_UNSIGNED(Types.INTEGER, Long.class),
    BIGINT(Types.BIGINT, Long.class),
    BIGINT_UNSIGNED(Types.BIGINT, BigInteger.class),
    SMALLINT(Types.SMALLINT, Integer.class),
    SMALLINT_UNSIGNED(Types.SMALLINT, Integer.class),  // 补充类型 1
    MEDIUMINT(Types.INTEGER, Integer.class),
    MEDIUMINT_UNSIGNED(Types.INTEGER, Integer.class),  // 补充类型 2
    TINYINT(Types.TINYINT, Integer.class),
    TINYINT_UNSIGNED(Types.TINYINT, Integer.class),    // 补充类型 3
    BOOLEAN(Types.BIT, Boolean.class),

    // ==================== 浮点类型 ====================
    FLOAT(Types.REAL, Float.class),
    DOUBLE(Types.DOUBLE, Double.class),
    DECIMAL(Types.DECIMAL, BigDecimal.class),

    // ==================== 字符串类型 ====================
    CHAR(Types.CHAR, String.class),
    VARCHAR(Types.VARCHAR, String.class),
    TEXT(Types.LONGVARCHAR, String.class),
    TINYTEXT(Types.VARCHAR, String.class),
    MEDIUMTEXT(Types.LONGVARCHAR, String.class),
    LONGTEXT(Types.LONGVARCHAR, String.class),
    ENUM(Types.CHAR, String.class),
    SET(Types.CHAR, String.class),
    CLOB(Types.CLOB, String.class),
    JSON(Types.LONGVARCHAR, String.class),

    // ==================== 二进制类型 ====================
    BLOB(Types.LONGVARBINARY, byte[].class),
    TINYBLOB(Types.VARBINARY, byte[].class),
    MEDIUMBLOB(Types.LONGVARBINARY, byte[].class),
    LONGBLOB(Types.LONGVARBINARY, byte[].class),
    BINARY(Types.BINARY, byte[].class),
    VARBINARY(Types.VARBINARY, byte[].class),

    // ==================== 日期时间类型 ====================
    DATE(Types.DATE, java.sql.Date.class),
    TIME(Types.TIME, java.sql.Time.class),
    DATETIME(Types.TIMESTAMP, LocalDateTime.class),
    TIMESTAMP(Types.TIMESTAMP, Timestamp.class),
    YEAR(Types.DATE, java.sql.Date.class),

    // =======================================
    UNSPECIFIED(0, Object.class);

    private final int jdbcType;
    private final Class<?> javaType;

    SqlType(int jdbcType, Class<?> javaType) {
        this.jdbcType = jdbcType;
        this.javaType = javaType;
    }

    /**
     * 根据 Java 类型推断 SQL 类型
     * 这个方法用于生成测试，或者参考
     */
    public static SqlType fromJavaType(Class<?> javaType) {
        if (javaType == null) return VARCHAR; // 默认类型

        // 处理标准类型
        if (String.class.equals(javaType)) return VARCHAR;
        if (Integer.class.equals(javaType)) return INT;
        if (Long.class.equals(javaType)) return BIGINT;
        if (Short.class.equals(javaType)) return SMALLINT;
        if (Byte.class.equals(javaType)) return TINYINT;
        if (BigInteger.class.equals(javaType)) return BIGINT_UNSIGNED;
        if (Float.class.equals(javaType)) return FLOAT;
        if (Double.class.equals(javaType)) return DOUBLE;
        if (BigDecimal.class.equals(javaType)) return DECIMAL;
        if (Boolean.class.equals(javaType)) return BOOLEAN;
        if (LocalDateTime.class.equals(javaType)) return DATETIME;
        if (LocalDate.class.equals(javaType)) return DATE;
        if (LocalTime.class.equals(javaType)) return TIME;
        if (byte[].class.equals(javaType)) return BLOB;
        if (Timestamp.class.equals(javaType)) return TIMESTAMP;

        // 处理原始类型（映射到包装类型）
        if (int.class.equals(javaType)) return INT;
        if (long.class.equals(javaType)) return BIGINT;
        if (short.class.equals(javaType)) return SMALLINT;
        if (byte.class.equals(javaType)) return TINYINT;
        if (float.class.equals(javaType)) return FLOAT;
        if (double.class.equals(javaType)) return DOUBLE;
        if (boolean.class.equals(javaType)) return BOOLEAN;


        return VARCHAR; // 默认类型
    }

    public int getJdbcType() {
        return jdbcType;
    }

    public boolean isString() {
        return String.class.equals(javaType);
    }

    public Class<?> getJavaType() {
        return javaType;
    }

    /**
     * 检查类型是否是整数类型
     */
    public boolean isIntegerType() {
        return Integer.class.equals(javaType) ||
                Long.class.equals(javaType) ||
                Short.class.equals(javaType) ||
                Byte.class.equals(javaType) ||
                BigInteger.class.equals(javaType);
    }

    /**
     * 检查类型是否是浮点类型
     */
    public boolean isFloatType() {
        return Float.class.equals(javaType) ||
                Double.class.equals(javaType) ||
                BigDecimal.class.equals(javaType);
    }

    /**
     * 检查类型是否需要指定大小（长度或精度）
     * 需要显式指定长度的类型包括：
     * - CHAR, VARCHAR: 需要指定字符长度
     * - DECIMAL: 需要指定精度和小数位数
     * - FLOAT, DOUBLE: 可以指定精度（可选）
     */
    public boolean hasLength() {
        return this == CHAR ||
                this == VARCHAR ||
                this == BINARY ||
                this == VARBINARY;
    }

    public boolean hasScale() {

        return this == DECIMAL || this == FLOAT || this == DOUBLE;
    }

    /**
     * 检查类型是否是日期时间类型
     */
    public boolean isDateTimeType() {
        return LocalDateTime.class.equals(javaType) ||
                Date.class.equals(javaType) ||
                LocalDate.class.equals(javaType) ||
                LocalTime.class.equals(javaType);
    }

    /**
     * 检查类型是否是二进制类型
     */
    public boolean isBinaryType() {
        return byte[].class.equals(javaType);
    }

    /**
     * 检查类型是否是无符号类型
     */
    public boolean isUnsigned() {
        return this == INT_UNSIGNED ||
                this == BIGINT_UNSIGNED ||
                this == SMALLINT_UNSIGNED ||
                this == TINYINT_UNSIGNED;
    }

    /**
     * 检查类型是否是文本类型
     */
    public boolean isTextType() {
        return this == TEXT ||
                this == TINYTEXT ||
                this == MEDIUMTEXT ||
                this == LONGTEXT ||
                this == CLOB;
    }
}
